S3のPresigned URLで作るリンクでファイルダウンロードを強制する
Amazon S3にはPresigned URL(署名付きURL)という機能があり、S3オブジェクトの限定的なアクセスを提供できます。
弊社ブログでもいくつかやり方が紹介されています。
- Boto3でS3のpre-signed URLを生成する | DevelopersIO
- Amazon S3 の署名付き URL (presigned URL) をマネジメントコンソールからお手軽に生成できるようになっていた | DevelopersIO
このPresigned URLをブラウザで開くと、その挙動はブラウザ依存で変わります。
ファイルの種類によってはブラウザで直接表示されたり、ダウンロードされたりする場合があります。
今回、ブラウザでの表示を避け、ファイルダウンロードを強制したいケースがあったので、その方法を共有します。
Content-Dispositionヘッダー
結論から言うと、Content-Disposition
ヘッダーを利用します。
Content-Disposition
ヘッダーは、HTTPレスポンスヘッダーの1つで、ファイルのインライン表示やダウンロード時の挙動を制御するために使用します。
Presigned URLを生成する際に、レスポンスにこの Content-Disposition
ヘッダーを設定できます。
Boto3を使った例
Pythonでboto3ライブラリを使ってPresigned URLを生成する例を紹介します。
Presigned URLを生成する際に、次の設定をしておくと、Presigned URLのアクセス時のレスポンスに Content-Disposition
ヘッダーが設定されます。
そうすると、生成したPresigned URLをブラウザで開くと、ファイルがダウンロードされる挙動となります。
具体的には次のようなコードです。
# バケット名,オブジェクト名
BUCKET_NAME = '<<YOUR S3 BUCKET NAME>>'
OBJECT_KEY_NAME = '<<YOUR S3 OBJECT KEY NAME>>'
import boto3
from botocore.exceptions import NoCredentialsError
def generate_presigned_url(bucket_name, object_key, filename=None, expiration=3600):
if filename is None:
filename = object_key
s3_client = boto3.client('s3')
try:
response = s3_client.generate_presigned_url(
'get_object',
Params={
'Bucket': bucket_name,
'Key': object_key,
'ResponseContentDisposition': 'attachment; filename="{}"'.format(filename)
},
ExpiresIn=expiration)
except NoCredentialsError:
print("Credentials not available")
return None
return response
if __name__=='__main__':
bucket_name = BUCKET_NAME
object_key = OBJECT_KEY_NAME
url = generate_presigned_url(bucket_name, object_key, 'sample.txt')
print(f"Presigned URL: {url}")
パラメーターの深堀り
generate_presigned_url
メソッドのパラメーターに何が使えるか、どのように考えれば良いでしょうか?
もう少し深堀りしてみます。
まずは、ドキュメントを見てみましょう。
正直、よくわからないですね。
この辺の記述と、Presigned URLの正体が AWS APIのリクエスト署名したURL であることから読み解いていきます。
Parameters:
- ClientMethod (string) – The client method to presign for
- Params (dict) – The parameters normally passed to ClientMethod.
- ExpiresIn (int) – The number of seconds the presigned url is valid for. By default it expires in an hour (3600 seconds)
- HttpMethod (string) – The http method to use on the generated url. By default, the http method is whatever is used in the method’s model.
おそらく generate_presigned_url
メソッドの ClientMethod
パラメーターは、 get_object
等メソッド名を文字列で受け取り、 Params
パラメーターには、get_object
メソッドのパラメーターがそのまま使えるのでしょう。
get_object
メソッドのドキュメントを見ると、 ResponseContentDisposition
というパラメーターがあり、これがレスポンスに Content-Disposition
ヘッダーを設定するためのパラメーターであることがわかります。
この前提でサンプルプログラムのようにパラメーターを設定してPresigned URLを生成し、次のように curl
コマンドでアクセスしてみると、 Content-Disposition
ヘッダーが設定されていることが確認できます。
$ PRESIGNED_URL="<<YOUR PRESIGNED URL>>"
$ curl -D - ${PRESIGNED_URL}
HTTP/1.1 200 OK
x-amz-id-2: dr65zHDCXfVByWA4oMSf+msizvqCiQk/vA1wOYtf4N5tRbdhIJ83jq1EwLdleK0199SPvmrFjnU=
x-amz-request-id: RF8CH96SBZTHM7KM
Date: Wed, 06 Nov 2024 08:32:17 GMT
Last-Modified: Sun, 31 Jan 2021 12:52:39 GMT
ETag: "ab41eff9c43c9837a78093369a174315"
Content-Disposition: attachment; filename="sample.txt"
Accept-Ranges: bytes
Content-Type: application/json
Server: AmazonS3
Content-Length: 35
{
"greeting": "Hello, World!"
}
なので、パラメーターの使い方はこの理解で合っていそうです。
おわりに
S3のPresigned URLでファイルダウンロードの強制を試してみました。
S3のPresigned URLで他にも制御できるレスポンスヘッダーがあるので、いろいろ活用できそうです。
例えば、 Content-Type
ヘッダーを設定しておくことで、ファイルのMIMEタイプを指定できます。
レスポンスヘッダーで挙動を制御できることを知っておくと、S3のPresigned URLがより便利に使えそうです。